package com.example.javascaffold.aspect;

import com.example.javascaffold.annotation.Render;
import com.example.javascaffold.utils.Ret;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;


/**
 * <p><strong>自动捕捉和输出日志</strong></p>
 * <p>
 * 减少try catch代码 同时输出规范化日志 <br>
 * 默认执行成功不打印param 执行失败打印param <br>
 * </p>
 * <li>
 * <p>
 *     <strong>示例1: @Render</strong> <br>
 *     结果: 执行成功打印执行时间 执行失败打印参数 <br>
 * </p>
 * </li>
 * <li>
 * <p>
 *     <strong>示例2: @Render(execTime = false, logSuccessParam = true)</strong> <br>
 *     结果: 不打印执行时间 执行成功时打印执行参数 <br>
 * </p>
 * </li>
 * @author song
 * @see Render
 * @since 16:28 2021/8/13
 **/
@Aspect
@Slf4j
@Component
public class RenderAspect {

    @Value("${spring.profiles.active}")
    private String runtime;

    /**
     * dev开发模式
     */
    private static final String DEV_RUNTIME = "dev";

    /**
     * prod开发模式
     */
    private static final String PROD_RUNTIME = "prod";

    @Around("@annotation(render)")
    public Object render(ProceedingJoinPoint proceedingJoinPoint, Render render) throws Throwable {
        // 获取 MethodSignature
        MethodSignature signature = (MethodSignature) proceedingJoinPoint.getSignature();
        // 获取方法的执行结果
        String className = proceedingJoinPoint.getTarget().getClass().getName();
        String methodName = signature.getMethod().getName();

        Ret<?> proceed = new Ret<>();
        try {
            long startTime = System.currentTimeMillis();
            proceed = (Ret<?>) proceedingJoinPoint.proceed();
            long endTime = System.currentTimeMillis();
            log.info(
                    "[" + className + " => " +
                            methodName + " => success => exec: {}]", endTime - startTime);
            Ret.success(proceed);
            return proceed;
        } catch (Exception e) {
            if (DEV_RUNTIME.equals(runtime)) {
                e.printStackTrace();
            }
            // 失败时 打印参数 和 异常
            Object[] params = proceedingJoinPoint.getArgs();
            log.error(
                    "[" + className + " => " +
                            methodName + " => error => exception: {}, param: {}]", e, params);
            Ret.fail(proceed, e);
        }
        return proceed;
    }

}
